package com.tarena.lbs.basic.web.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.basic.web.repository.AdminRepository;
import com.tarena.lbs.basic.web.repository.BusinessRepository;
import com.tarena.lbs.basic.web.repository.StoreRepository;
import com.tarena.lbs.basic.web.source.BasicOutputSource;
import com.tarena.lbs.basic.web.utils.AuthenticationContextUtils;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.entity.StoreSearchEntity;
import com.tarena.lbs.pojo.basic.event.LocationEvent;
import com.tarena.lbs.pojo.basic.param.StoreParam;
import com.tarena.lbs.pojo.basic.param.UserLocationParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.po.StorePO;
import com.tarena.lbs.pojo.basic.query.AreaStoreQuery;
import com.tarena.lbs.pojo.basic.query.StoreQuery;
import com.tarena.lbs.pojo.basic.vo.StoreVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StoreService {
    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private StoreRepository storeRepository;
    @Autowired
    private BusinessRepository businessRepository;
    @DubboReference
    private AttachApi attachApi;
    @Autowired
    private BasicOutputSource outputSource;
    public PageResult<StoreVO> pageList(StoreQuery query) throws BusinessException {
        //1.准备一个PageResult 封装 pageNo pageSize total=100L
        PageResult<StoreVO> voPage=
                new PageResult<>(query.getPageSize(),query.getPageNo());
        voPage.setTotal(100l);
        //2.获取登录用户角色
        UserPrinciple userPrinciple=getUserPrinciple();
        //2.1 如果是shop角色 读取admin详情 获取admin的businessId商家id
        if (userPrinciple.getRole()==Roles.SHOP){
            //说明当前请求用户 是个商家管理员 查询businessId
            AdminPO adminPO = adminRepository.getById(userPrinciple.getId());
            Asserts.isTrue(adminPO==null,new BusinessException("-2","商家账号不存在"));
            //不为空 获取商家id
            Integer businessId=adminPO.getBusinessId();
            query.setBusinessId(businessId);
        }
        //3.查询列表 select * from lbs_store where business_id=?
        List<StorePO> pos=getStoreList(query);
        //4.查询pos转化vos 封装pageResult中
        if (pos!=null&& pos.size()>0){
            voPage.setObjects(pos.stream().map(po->{
                StoreVO vo=new StoreVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList()));
        }
        return voPage;
    }

    private List<StorePO> getStoreList(StoreQuery query) {
        //只关注一个条件 query 的businessId是否是空
        QueryWrapper<StorePO> queryWrapper=new QueryWrapper<>();
        if (query.getBusinessId()!=null){
            queryWrapper.eq("business_id",query.getBusinessId());
        }
        return storeRepository.list(queryWrapper);
    }

    private UserPrinciple getUserPrinciple() throws BusinessException {
        //解析认证 拿到对象 判断非空
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","认证解析失败"));
        return userPrinciple;
    }

    public void addStore(StoreParam storeParam) throws BusinessException {
        //1.checkRole检查角色 必须只能是SHOP角色
        checkRole(Roles.SHOP);
        //2.检查商家是否存在
        checkBusiness(storeParam.getBusinessId());
        //3.将param转化成po
        StorePO poParam=param2po(storeParam);
        //4.将poParam 调用数据层写入 同时写入到es和mysql 交给仓储层做
        storeRepository.saveData(poParam);
        //5.绑定图片 logo 300 storeId images 400 storeId
        bindPictures(storeParam,poParam.getId());
    }

    private void bindPictures(StoreParam storeParam, Integer bizId) {
        //在这个方法 远程调用图片绑定2个类型 门店  logo
        List<PicUpdateParam> picParams=new ArrayList<>();
        //logo是单张
        PicUpdateParam logoParam=new PicUpdateParam();
        logoParam.setBusinessType(300);
        logoParam.setBusinessId(bizId);
        logoParam.setId(Integer.valueOf(storeParam.getStoreLogo()));
        picParams.add(logoParam);
        //images门店图片 多张
        List<PicUpdateParam> imageParams=null;
        List<String> storeImagesIds = storeParam.getStoreImagesIds();
        imageParams=storeImagesIds.stream().map(imgId->{
            PicUpdateParam param=new PicUpdateParam();
            param.setBusinessType(400);
            param.setBusinessId(bizId);
            param.setId(Integer.valueOf(imgId));
            return param;
        }).collect(Collectors.toList());
        picParams.addAll(imageParams);
        attachApi.batchUpdateBusiness(picParams);
    }

    private StorePO param2po(StoreParam storeParam) {
        //将param中能考被的属性 全都拷贝
        StorePO po=new StorePO();
        BeanUtils.copyProperties(storeParam,po);
        //1.店铺状态 前端没传 0 正常 1 禁用
        po.setStoreStatus(0);
        //2.店铺的创建修改时间
        Date now=new Date();
        po.setCreateTime(now);
        po.setUpdateTime(now);
        //3.地理位置 入参latitude longitude 但是po属性字段 storeLatitude storeLongitude
        po.setStoreLatitude(storeParam.getLatitude());
        po.setStoreLongitude(storeParam.getLongitude());
        //4.手动将入参的 门店图片数组 转化成使用 , 隔开的字符串
        //[177,178,179] ==> "177,178,179"
        List<String> storeImagesIds = storeParam.getStoreImagesIds();
        String images="";
        if (storeImagesIds!=null&&storeImagesIds.size()>0){
            //循环 判断元素是否已经到最后一个
            for(int i=0;i<storeImagesIds.size();i++){
                //数组 是最后一个元素 不拼接 ,
                if (i==storeImagesIds.size()-1){
                    images=images+storeImagesIds.get(i);
                }else{
                    //数组 不是最后元素 拼接,
                    images=images+storeImagesIds.get(i)+",";
                }
            }
        }
        log.info("当前店铺:{},门店图片images:{}",storeParam.getStoreName(),images);
        po.setStoreImagesId(images);
        return po;
    }

    private void checkBusiness(Integer businessId) throws BusinessException {
        //使用businessId 获取businessPO 判断非空
        BusinessPO po = businessRepository.getById(businessId);
        Asserts.isTrue(po==null,new BusinessException("-2","商家信息不存在"));
    }

    private void checkRole(Roles role) throws BusinessException {
        //当前系统 有一个过滤器 解析jwt 拿到userPrinciple 所有业务功能都在过滤器下游可以获取传参
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        //断言判断 如果认证对象是空 抛出异常
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","认证解析失败"));
        //从认证对象拿到发起请求的用户 真实角色
        Roles userRole = userPrinciple.getRole();
        //断言 必须要求用户角色 和入参角色相等 ,不相等 抛异常
        Asserts.isTrue(userRole!=role,new BusinessException("-2","新增商家需要平台管理员"));
    }

    public PageResult<StoreVO> getCityStore(AreaStoreQuery query) throws BusinessException {
        //1.拿到用户di
        UserPrinciple userPrinciple = getUserPrinciple();
        Integer userId=userPrinciple.getId();
        //2.读取登录用户 商家用户 所属商家
        AdminPO adminPO = adminRepository.getById(userId);
        //UNDO 不断言
        List<StorePO> pos= getCityStores(query,adminPO.getBusinessId());
        List<StoreVO> vos=null;
        if (pos!=null&&pos.size()>0){
            vos= pos.stream().map(po->{
                StoreVO vo=new StoreVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        //3.封装一个下分也对象result
        PageResult<StoreVO> result=new PageResult<>(10,1);
        result.setTotal(100l);
        result.setObjects(vos);
        return result;
    }

    private List<StorePO> getCityStores(AreaStoreQuery query, Integer businessId) {
        //select * from lbs_store where business_id= and ( province in  or city in or area in)
        QueryWrapper<StorePO> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("business_id",businessId)
                .and(
                        qw->qw.in("province_id",query.getCityIdList())
                                .or().in("city_id",query.getCityIdList())
                                .or().in("area_id",query.getCityIdList())
                );
        return storeRepository.list(queryWrapper);
    }

    public void location(UserLocationParam param) throws BusinessException {
        //1.解析认证数据拿到userId
        UserPrinciple userPrinciple = getUserPrinciple();
        Integer userId=userPrinciple.getId();
        //2.调用仓储层查询附近店铺 最近5个
        List<StoreSearchEntity> entities=storeRepository.getNearStores(param);
        //3.如果店铺非空,封装事件消息 通过output通道发送
        MessageChannel channel = outputSource.getBasicStoreLocationOutput();
        if (entities!=null&&entities.size()>0){
            //定义一个事件消息 封装本次的店铺地理查询定位信息
            //每个店铺 都要发送一个事件,让消费者 marketing去判断这个店铺有没有可以发给用户的优惠券
            for (StoreSearchEntity entity : entities) {
                //1.封装message
                LocationEvent event=new LocationEvent();
                event.setUserId(userId);
                event.setStoreId(entity.getId());
                Message<LocationEvent> message = MessageBuilder.withPayload(event).build();
                //2.发送消息到目标
                channel.send(message);
                log.info("消息数据:{},发送成功",event);
            }
        }
    }
}
